﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;

namespace HttpAuth
{
    public class NonceCounterItem
    {
        private List<int> _PassedCounts;

        public List<int> PassedCounts {
            get { return _PassedCounts; }
            set { _PassedCounts = value; LastUpdate = DateTime.Now; } 
        }

        public DateTime LastUpdate { get; set; }

        public NonceCounterItem()
        {
            this.PassedCounts = new List<int>();
        }

        public bool RegistPassedCount(int intnc)
        {
            if (this.PassedCounts.Contains(intnc) || intnc <= (this.PassedCounts.Any() ? this.PassedCounts.Min() : 0))
            {
                return false;
            }
            this.PassedCounts.Add(intnc);

            MinimizeCounts();

            const int maxCountBuff = 30;
            var toKeep = this.PassedCounts
                .OrderByDescending(n => n)
                .Take(maxCountBuff)
                .ToList();
            var toRemove = this.PassedCounts
                .Where(n => toKeep.Contains(n) == false)
                .ToList();
            toRemove.ForEach(n => this.PassedCounts.Remove(n));

            if (toRemove.Any()) MinimizeCounts();

            return true;
        }

        private void MinimizeCounts()
        {
            this.PassedCounts
                .OrderBy(n => n)
                .TakeWhile(n => this.PassedCounts.Contains(n + 1))
                .ToList()
                .ForEach(n => this.PassedCounts.Remove(n));
        }
    }

    public class NonceCouner : ConcurrentDictionary<string, NonceCounterItem>
    {
        public string NewNonce()
        {
            var nonce = Guid.NewGuid().ToString("N");
            this.AddOrUpdate(nonce, new NonceCounterItem(), (_, __) => null);
            return nonce;
        }

        public void Sweep(int timeout)
        {
            this.Where(kvp => (DateTime.Now - kvp.Value.LastUpdate).Minutes > timeout)
                .Select(kvp => kvp.Key)
                .ToList()
                .ForEach(key => { var _ = default(NonceCounterItem); this.TryRemove(key, out _); });
        }
    }
}
